package com.example.threadcode.higherLeverThree.Dictionary;

import java.util.HashMap;
import java.util.Map;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 默认主线程首先创建word和definitions字符串数组.他们被声明为final类型因为他们将会被匿名类访问
 * 之后创建一个map,用来储存word/definitions 实体,创建获取读写锁.
 */
public class Dictionary
{
   public static void main(String[] args)
   {
      final String[] words =
      {
         "hypocalcemia",
         "prolixity",
         "assiduous",
         "indefatigable",
         "castellan"
      };

      final String[] definitions =
      {
         "a deficiency of calcium in the blood",
         "unduly prolonged or drawn out",
         "showing great care, attention, and effort",
         "able to work or continue for a lengthy time without tiring",
         "the govenor or warden of a castle or fort"
      };

      final Map<String, String> dictionary = new HashMap<String, String>();

      ReadWriteLock rwl = new ReentrantReadWriteLock(true);
      final Lock rlock = rwl.readLock();
      final Lock wlock = rwl.writeLock();
      /**
       * runnable的写方法 在里面迭代出words数组的单词,每次迭代锁定写锁,
       * 当方法返回时,写线程需拥有独占的写锁才能更新map.通过map的put方法来实现更新.
       * 输入信息后,用来验证已经添加了单词,写线程释放写锁并且休眠1毫秒去模拟处理其他工作的样子
       * 基于线程池的执行器被用于调用写线程的runnable方法
       *
       */
      Runnable writer = () ->
                        {
                           for (int i = 0; i < words.length; i++)
                           {
                              wlock.lock(); 
                              try
                              {
                                 dictionary.put(words[i], 
                                                definitions[i]);
                                 System.out.println("writer storing " + 
                                                    words[i] + " entry");
                              }
                              finally
                              {
//                                 加了多少次锁就要释放多少次. 不然这程序不能向下执行.
                                 wlock.unlock();
                              }

                              try
                              {
                                 Thread.sleep(0);
                              }
                              catch (InterruptedException ie)
                              {
                                 System.err.println("writer " + 
                                                    "interrupted");
                              }
                           }
                        };
      ExecutorService es = Executors.newFixedThreadPool(1);
      es.submit(writer);

      /**
       * runnable的读方法,run方法里重复获取读锁,随机访问map里的实体,输出這个实体,然后释放读锁
       * 基于线程池的执行器被用于调用读线程的runnable方法
       * 虽然不会抛出异常,但是还是用try/finally的良好语义去做为了保证锁释放.
       */
      Runnable reader = () ->
                        {
                           while (true)
                           {
                              rlock.lock();
                              try
                              {
                                 int i = (int) (Math.random() * 
                                                words.length);
                                 System.out.println("reader accessing " +
                                                    words[i] + ": " +
                                                    dictionary.get(words[i])
                                                    + " entry");
                              }
                              finally
                              {
                                 rlock.unlock();
                              }
                           }
                        };
      es = Executors.newFixedThreadPool(1);
      es.submit(reader);
   }
}